/*
 * Copyright (C) 2011 Michael Widmer <widmm8@bfh.ch>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package ch.bfh.aeneas.navigation.around;


import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.content.SharedPreferences;
import android.location.Location;
import android.os.Bundle;
import android.os.IBinder;
import android.os.Parcelable;
import android.util.Log;
import ch.bfh.aeneas.R;
import ch.bfh.aeneas.exchange.intent.AeneasIntent;
import ch.bfh.aeneas.exchange.data.Node;
import ch.bfh.aeneas.navigation.app.NavigationActivity;
import ch.bfh.aeneas.navigation.app.NavigationService.NavigationServiceBinder;
import ch.bfh.aeneas.navigation.guide.GuideMe;
import ch.bfh.aeneas.exchange.utils.DataConverter;


/**
 * AroundMe tries to get places around the current location and displays them
 * orderd in categories to the user. After selecting one place het gets told
 * about direction and distance to that place.
 * @author Michael Widmer <widmm8@bfh.ch>
 */
public class AroundMe extends NavigationActivity {

    protected ServiceConnection mAroundConnection = new ServiceConnection() {
        public void onServiceConnected(ComponentName arg0, IBinder arg1) {
            mAroundService = (AroundService) ((NavigationServiceBinder) arg1).getService();
            mAroundService.addOnResultsListener(mResultsListener);
            mAroundStarted = true;
            checkRequirements();
        }

        public void onServiceDisconnected(ComponentName arg0) {
            mAroundStarted = false;
            stopListening();
        }        
    };
    
    private static final int PICK_CATEGORY = 1;
    private static final int PICK_NODE = 2;
    private static final int GET_DIRECTION = 3;
    private static final int SET_RANGE = 4;
    
    private static final String LOG_TAG = "AroundMe";
    
    protected AroundService mAroundService;
    protected Boolean mAroundStarted;
    protected int mAskRange;
    protected PoiSorter mSorter;
    protected boolean mHasResult;
    protected boolean mProcessing;
    protected boolean mWaitingForRequest;
    protected Location mAskedLocation;
    protected String mSelectedCategory;
    
    @Override
    /**
     * {@inheritDoc}
     */
    public void onCreate(Bundle icicle) {
        super.onCreate(icicle,R.layout.aroundme);
        
        mAroundStarted = false;
        mHasResult = false;
        mProcessing = false;
        mWaitingForRequest = false;
        
        mSelectedCategory = "";
        
        mAskRange = -1;
    }
    
    @Override
    /**
     * {@inheritDoc}
     */
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        Log.i(LOG_TAG, "Received resultCode: "+resultCode+" and requestCode: "+requestCode);
        if(resultCode == Activity.RESULT_OK) {
            mProcessing = true;
            Log.i(LOG_TAG,"Answer of activity was positive...");
            Bundle extras = data.getExtras();
            int index = extras.getInt("selectedIndex");
            String item = extras.getString("selectedValue");
            
            if(requestCode == PICK_CATEGORY) {
                //String[] categories = mSorter.getCategoriesArray();
                
                Log.i(LOG_TAG, "Picked category '"+item+"' at position: "+index);
                
                mSelectedCategory = item;
                
                //String category = categories[index];
                showNodeList(item);
            } else if(requestCode == PICK_NODE) {
                
                outputDistances(index);
                Log.i(LOG_TAG, "Picked node at position: "+index);
                
            } else if(requestCode == GET_DIRECTION) {
                
                Log.i(LOG_TAG, "Outputted distances!");
                if(data.hasExtra("hour") && data.hasExtra("distance")) {
                    
                    String hour = Integer.toString(data.getIntExtra("hour", 0));
                    String distance = Integer.toString(Math.round(data.getFloatExtra("distance", 0.0f)));
                    
                    speech(super.getResources().getString(R.string.guide_order_rotate)+" "+hour+" "+super.getResources().getString(R.string.guide_order_rot_unit));
                    speech(super.getResources().getString(R.string.guide_order_dist)+" "+distance+" "+super.getResources().getString(R.string.guide_order_dist_unit));
                }
                mProcessing = false;
                
            } else if(requestCode == SET_RANGE) {
                
                int range = data.getIntExtra("input", 100);
                Log.i(LOG_TAG, "Parsed input as int: "+range);
                
                mAskRange = range;
                mWaitingForRequest = true;
            }
        } else if(resultCode == Activity.RESULT_CANCELED) {
            
            Log.i(LOG_TAG, "Answer of activity was negative...");
            Log.e(LOG_TAG, "In Fallback!");
            mProcessing = false;
            //showCategoryList();
            if(requestCode == SET_RANGE) {
                finish();
            } else if(requestCode == PICK_NODE) {
                mSelectedCategory = "";
            } else if(requestCode == PICK_CATEGORY) {
                mHasResult = false;
            }
            
        }
    }
    
    @Override
    /**
     * {@inheritDoc}
     */
    public void onResume() {
        super.onResume();
        
        if(mHasResult && !mProcessing) {
            if(mSelectedCategory.equals("")) {
                Log.e(LOG_TAG, "In Resume!");
                showCategoryList();
            } else {
                showNodeList(mSelectedCategory);
            }
        } else if(!mProcessing) {
            mProcessing = true;
            askForRange();
        } else {
            bindService(new Intent(this, AroundService.class),mAroundConnection,Context.BIND_AUTO_CREATE);
        }
    }
    
    @Override
    /**
     * {@inheritDoc}
     */
    public void onPause() {
        super.onPause();
        
        if(mAroundStarted) {
            mAroundStarted = false;
            mAroundService = null;
            unbindService(mAroundConnection);
        }
    }

    @Override
    /**
     * {@inheritDoc}
     */
    protected void onPositionDisconnect() {
        stopListening();
    }

    @Override
    /**
     * {@inheritDoc}
     */
    protected void onPositionConnected() {
        checkRequirements();
    }
    
    @Override
    /**
     * {@inheritDoc}
     */
    protected void onPositionReceivedFirst(Location l) {
        if(!mProcessing && !mHasResult) {
            speech(getString(R.string.state_pos_found));
        } else {
            if(mWaitingForRequest) {
                startRequest(l);
            }
        }
    }
    
    @Override
    /**
     * {@inheritDoc}
     */
    protected void onPositionReceived(Location l) {
        if(mWaitingForRequest) {
            startRequest(l);
        }
    }

    @Override
    /**
     * {@inheritDoc}
     */
    protected void onRequestFinished(int request) {
        Log.i(LOG_TAG, "Request finished");
        super.onRequestFinished(request);
        
        mSorter = new PoiSorter();
        for(int i = 0; i < mAnswers.size(); i++) {
            handleAnswer(mSorter, mAnswers.get(i));
        }
        mHasResult = true;
        
        if(mSorter.getNodeCount() > 0) {
            showCategoryList();
        } else {
            speech(getString(R.string.around_empty_result));
        }
    }
    
    private void askForRange() {
        SharedPreferences p = super.getApplicationPreferences();
        String range = p.getString("around_range", "-1");
        
        Intent i = new Intent(AeneasIntent.ACTION_INPUT);
        i.addCategory(AeneasIntent.CATEGORY_DATA);
        i.putExtra("default",range);
        i.putExtra("numeric", true);
        i.putExtra("title", getString(R.string.around_enter_radius));
        
        startActivityForResult(i, SET_RANGE);
    }
    
    protected void checkRequirements() {
        if(mAroundStarted && isPositionManagerReady()) {
            startListening();
        }
    }
    
    private void startRequest(Location l) {
        if(mWaitingForRequest) {
            mAskedLocation = l;
            mWaitingForRequest = false;
            mAroundService.whatsAround(mAskedLocation, mAskRange);
        }
    }
    
    protected void handleAnswer(PoiSorter sorter, Intent intent) {
        
        Bundle extras = intent.getExtras();
        if(extras == null) {
            Log.e(LOG_TAG, "No extras found :(");
            return;
        }
        
        Node node;
        int acounter = 0;
        
        while(extras.containsKey("address"+acounter)) {
            Parcelable n = extras.getParcelable("address"+acounter);
            
            if(n instanceof Node) {
                node = (Node) n;
                sorter.addPoi(node);
            }
            acounter++;
        }
    }

    private void showCategoryList() {
        Log.i(LOG_TAG, "Trying to display categories!");
        
        if(mSorter == null) {
            return;
        }
        
        String[] categories = mSorter.getCategoriesArray();
        
        String title = super.getResources().getString(R.string.around_result_categories);
        
        Intent i = new Intent(AeneasIntent.ACTION_SELECT);
        i.addCategory(AeneasIntent.CATEGORY_STRING);
        i.putExtra("values", categories);
        i.putExtra("title", title);
        
        startActivityForResult(i,PICK_CATEGORY);
    }

    private void showNodeList(String category) {
        if(mSorter == null)
            return;
        
        Log.i(LOG_TAG, "Trying to display nodes for category: "+category);
        
        String[] nodes = mSorter.getNodeNamesArray(category);
        
        String title = super.getResources().getString(R.string.around_result_places);
        
        Intent i = new Intent(AeneasIntent.ACTION_SELECT);
        i.addCategory(AeneasIntent.CATEGORY_STRING);
        i.putExtra("values", nodes);
        i.putExtra("title", title);
        
        startActivityForResult(i,PICK_NODE);
    }

    private void outputDistances(int index) {
        Node toNode = mSorter.getNodeFromCategory(mSelectedCategory, index);
        Location to = DataConverter.node2Location(toNode);
        Intent i = new Intent(this, GuideMe.class);
        i.putExtra("from", mAskedLocation);
        i.putExtra("to", to);
        
        startActivityForResult(i,GET_DIRECTION);
    }
}